<template>
  <vue-flowchart-editor ref="flowChart" class="vue-flowchart-editor">
    <el-container>
      <el-aside  style="width:230px" >
        <algorithm-category-panel style="position: relative;width: 230px;" :node-items="algorithmList"/>
      </el-aside>
      <el-container>
        <el-header class="vfe-chart-header" style="height:5px;">
          <editor-toolbar :chart-data="flowChartData" :read-only="flowStatus" />
        </el-header>
        <el-main style="height:100%;border:solid 1px green;border-bottom: none ">
          <flow
            :data="flowChartData"
            :no-end-edge="false"
            :on-click="handleClick"
            :on-node-click="handleNodeClick"
            :on-node-double-click="handleNodeDoubleClick"
            :on-node-mouse-leave="handleNodeMouseLeave"
            :on-before-change="handleBeforeChange"
            :on-after-change="handleAfterChange"
            :graph="graphConfig"
          />
          <div class="tooltip">
            <template v-for="item in tooltipData">
              <p :key="item.name">
                {{ item.name }}{{ item.name }}: {{ item.value }}
              </p>
            </template>
          </div>
          <!-- 节点配置弹窗 -->
          <select-factory-form
            :algorithm-type="algorithmTypeName"
            :dialog-visible="dialogVisible"
            @close-dialog="closeDialog"
          />
          <!-- 右键菜单 -->
          <editor-context-menu v-if="!flowStatus" />
          <register-edge
            name="custom-polyline"
            extend="flow-polyline"
            :config="customEdgeConfig"
          />
          <!--savebeforerun的目的是在运行之前将流图中的数据进行保存-->
          <custom-command
            :flowchart-id="flowchartId"
            :save="saveChartData"
            :download="downloadImage"
            :savebeforerun="savebeforerun"
          />
        </el-main>
        <!--消息推送模块 start-->
<!--        <new-console :flow-chart-id="this.flowchartId" @task-finish = "renovatePage"></new-console>-->
        <!--消息推送模块 end-->
      </el-container>
    </el-container>
  </vue-flowchart-editor>
</template>

<script>
import VueFlowchartEditor, { Flow, RegisterEdge } from 'vue-flowchart-editor'
import EditorToolbar from './components/Toolbar'
import AlgorithmCategoryPanel from './algorithmCategoryPanel'
import EditorContextMenu from './components/ContextMenu'
import CustomCommand from './components/CustomCommand'
import { cloneDeep, throttle } from 'lodash'
import selectFactoryForm from './platformComponents/selectFactoryForm'
import axios from 'axios'
import NewConsole from "@/views/system/flow/workbench/components/NewConsole";
// import Myconsole from './components/Console'
export default {
  name: 'FlowAlgorithmEditor',

  components: {
    VueFlowchartEditor,
    Flow,
    EditorToolbar,
    EditorContextMenu,
    CustomCommand,
    RegisterEdge,
    AlgorithmCategoryPanel,
    selectFactoryForm,
    // Myconsole,
    NewConsole

  },

  props: [
    'flowchartId',
    'readOnly',
    'toggleReadOnly',
    'chartData',
    'chartDataNodeItems',
    'saveData',
    'algorithmCategoryList',
    'savebeforerun'
  ],
  // todo - 考虑传递id的方式
  provide() {
    return {
      flowchartId: this.flowchartId
    }
  },

  data() {
    return {
      // 存放后端，返回的消息信息
      termInfo:["aa"],
      flowStatus:'',
      edgeNum: 1,
      edgeoutputInfo: {
        id: ''
      },
      temp_info: {
        sourceID: '',
        targetID: ''
      },
      original_info: {
        id: ''
      },

      dialogVisible: false, // 弹出框是否显示
      algorithmTypeName: 'defalut',
      flowChartData: this.chartData,
      algorithmList: this.algorithmCategoryList,
      graphConfig: {
        mode: 'readOnly'
      },
      customEdgeConfig: {
        getActivedStyle(/* item*/) {
          return {
            lineWidth: 3
          }
        },
        getSelectedStyle(/* item*/) {
          return {
            lineWidth: 3
          }
        }
      },
      tooltipDom: {
        style:{
          display:''
        }
      },
      tooltipShow: true,
      tooltipData: [],
      es: {}
    }
  },
  created() {
    console.log(this.flowChartData)
    this.flowStatus = this.readOnly
    console.log('readonly',this.readOnly)
  },
  mounted() {
    // 类似提前声明变量 进入页面内容全部渲染完成后自动引函数
    // 2021-01-29 修改函数功能，变成由后端返回具体处理信息
    // this.tooltipDom = document.getElementsByClassName('tooltip')[0]
    // const url = `http://localhost:8000/datalab/event/${this.flowchartId}`
    // this.es = new EventSource(url)  // 1：向服务器来请求url  2： 监听服务器返回的响应
    // this.es.addEventListener('message', (event) => {
    //   // this.logMessage(event.data)
    //   this.termInfo.push(event.data)
    // })
    // this.es.addEventListener('error', (event) => {
    //   console.log('task error', event)
    //   this.es.close()
    //   if (event.readyState === EventSource.CLOSED) {
    //     this.logMessage('event close')
    //     // this.$emit('toggle-read-only')
    //   }
    // })
    // this.es.addEventListener('close', (event) => {
    //   this.logMessage(event.type)
    //   this.es.close()
    // })
    // this.es.addEventListener('complete', async (event) => {
    //   await this.fetchGraphData()
    //   this.logMessage('Task complete', true)
    // })

    // 消息模块，消息窗口滚动函数
    // this.scrollToBottom()
  },
  // updated() {
  //   // 操作消息模块，消息窗口滚动函数
  //   this.scrollToBottom()
  // },
  async beforeDestroy() {
    // this.es.close()
    if (!this.readOnly) {
      const { save } = this.$refs.flowChart.propsAPI
      const data = save()
      try {
        const response = await axios.put(
          `http://localhost:8000/datalab/flowchart/${this.flowchartId}`,
          {
            read_only: this.readOnly,
            nodes: data.nodes ? JSON.stringify(data.nodes) : '[]',
            edges: data.edges ? JSON.stringify(data.edges) : '[]'
          }
        )
        console.log(response)
      } catch (err) {
        console.log(err)
      }
    }
  },
  methods: {
    // 关闭弹出的配置窗口
    closeDialog() {
      this.dialogVisible = false
      this.algorithmTypeName = 'default' //如果不修改的话再次单击的时候algorithmtype仍然存储上个节点的类型 会继续执行上个节点的create方法。
    },
    async renovatePage() {
      await this.fetchGraphData()
      console.log('执行完成，刷新页面')
    },
    // 处理编辑器内点击事件
    handleClick(e) {
      console.log(e)
      console.log('handle click')
      if (this.readOnly && !e.item) {
        this.tooltipDom.style.display = 'none'
      }
    },
    // 处理节点点击事件
    handleNodeClick(e) {
      console.log('handkle nodeclick')
    },
    // 处理节点双击事件
    handleNodeDoubleClick(e) {
      console.log('handle double click node')
      // 双击该节点，将左侧算法列表中model.label信息赋值
      this.algorithmTypeName = e.item.model.label
      this.dialogVisible = true
    },
    // 鼠标离开处理，执行一个节流函数
    handleNodeMouseLeave: throttle(
      function () {
        // if (this.readOnly) {
        //   console.log(e)
        //   this.tooltipDom.style.display = 'none'
        // }
      },
      1000,
      {
        leading: false,
        trailing: true
      }
    ),
    // 流程图数据发生变化前
    handleBeforeChange(e) {
      if (!this.readOnly) {
        const { action, item } = e
        const { save, remove } = this.$refs.flowChart.propsAPI
        // 触发删除事件，则删除之后的边和节点
        if (action === 'remove') {
          console.log('e:', e)
          if (item.isEdge) {
            console.log('边item', item)
            remove(item.target.id)
          } else if (item.isNode) {
            if(save.edges){
              const forkEdges = save().edges.filter((edge) => {
                  return edge.source === item.id
                }
              )// edges这个数组调用箭头函数，edges数组中的元素作为形参传入箭头函数中的edge形参
              console.log('节点item：', item)
              console.log('forkEdges', forkEdges)
              forkEdges.forEach((edge) => {
                remove(edge.target)
              })
            }
          }
        }
      }
    },
    // 流程图数据发生变化后
    handleAfterChange(e) {
      console.log('enter handleAfterChange:', e)
      if (!this.readOnly) {
        const { action, item, originModel, updateModel } = e
        const {
          read,
          save,
          remove,
          find,
          update
        } = this.$refs.flowChart.propsAPI

        // // 处理节点的更新事件
        // if (action === 'update' && item.isNode) {
        //   console.log('节点的更新事件', e)
        //   // 节点executed从true变为false，意味着修改了节点的配置信息，之后节点的配置应当失效
        //   if (originModel.executed === true && updateModel.executed === false) {
        //     const forkEdges = save().edges.filter((edge) => {
        //       return edge.source === item.id
        //     })
        //     forkEdges.forEach((edge) => {
        //       const targetNode = find(edge.target)
        //       const nodeModel = targetNode.getModel()
        //       if (nodeModel.executed === true) {
        //         const newModel = Object.assign({}, cloneDeep(nodeModel))
        //         newModel.executed = false
        //         newModel.config = Object.assign(
        //           {},
        //           cloneDeep(this.getDefaultConfig(nodeModel.label))
        //         )
        //         update(targetNode, newModel)
        //       }
        //     })
        //   }
        // }

        // 处理边的更新事件，只允许锚点的变更
        if (action === 'update' && item.isEdge) {
          console.log('边的更新事件')
          const graphData = save()
          graphData.edges.forEach((edge) => {
            if (edge.id === item.id) {
              if (
                edge.source !== originModel.source ||
                  edge.target !== originModel.target
              ) {
                edge.source = originModel.source
                edge.sourceAnchor = originModel.sourceAnchor
                edge.target = originModel.target
                edge.targetAnchor = originModel.targetAnchor
                read(graphData)
              }
            }
          })
          return
        }

        // 处理边的添加事件 单节点输入不允许一个节点连接有多条边  多节点输入不允许超过两条边
        // if (action === 'add' && item.isEdge) {
        //   console.log('边的添加事件')
        //   const source_model = find(item.source.id).getModel()
        //   const target_model = find(item.target.id).getModel()
        //   //单输入的target节点的flag为false并且sourcemodel的execute状态为已执行才可以连接
        //   if (source_model.flag && !target_model.flag && source_model.execute == true) {
        //     target_model.flag = true
        //     // 如果是双输入节点 那么允许的输入值减一
        //     if (target_model.isAggregator) {
        //       // 2-1
        //       target_model.acceptedInput = target_model.acceptedInput - 1
        //     }
        //     // update(target, model)
        //   }
        //   // 双输入节点连接一条边之后还可以继续连接第二条边
        //   else if (
        //     source_model.flag &&
        //     target_model.flag &&
        //     target_model.isAggregator &&
        //     target_model.acceptedInput > 0 &&
        //     source_model.execute == true
        //   ) {
        //     target_model.acceptedInput = target_model.acceptedInput - 1
        //   } else {
        //     // 错误连接，在不触发删除事件的情况下删除
        //     const graphData = save()
        //     graphData.edges = graphData.edges.filter((edge) => {
        //       return edge.id !== item.id
        //     })
        //     read(graphData)
        //   }
        //   return
        // }
      }
      console.log('enter handleAfterChange finish')
    },
    // 获取指定算法的默认配置  找到相对应的信息之后便返回了 没有全部的遍历algorithmList
    getDefaultConfig(nodeLabel) {
      for (const algorithmGroup of this.algorithmList) {
        for (const algorithm of algorithmGroup.algorithm) {
          if (algorithm.model.label === nodeLabel) {
            return algorithm.model.config
          }
        }
      }
      return {}
    },
    async fetchGraphData() {
      // this.logMessage('reload data')
      const { read } = this.$refs.flowChart.propsAPI
      try {
        const response = await axios.get(`/api/datalab/flowchart/${this.flowchartId}`)
        this.flowStatus = response.data.read_only
        console.log('flowStatus',this.flowStatus)
        read({
          nodes: JSON.parse(response.data.nodes),
          edges: JSON.parse(response.data.edges)
        })
    }
      catch (err) {
        console.log(err)
      }
    },
    saveChartData(data) {
      this.$emit('save-data', data)
    },

    _downloadImage(data, filename = 'flowchart.png') {
      const a = document.createElement('a')
      a.href = data
      a.download = filename
      document.body.appendChild(a)
      a.click()
    },

    // logMessage(msg, withTime = false) {
    //   if (withTime) {
    //     this.$refs.myconsole.writeWithTime(msg)
    //   } else {
    //     this.$refs.myconsole.write(msg)
    //   }
    // },
    downloadImage() {
      const page = this.$refs['flowChart'].propsAPI.editor.getCurrentPage()
      this._downloadImage(page.saveImage().toDataURL('image/png'))
    }
  }
}
</script>

<style lang="less" scoped>
  .scroll-info>ul{

  }
  .scroll-info-li{
    height:20px;
    font-size: 14px;
    border-bottom: #f0f0f0 1px solid;
  }
  .vue-flowchart-editor {
    display: flex;
    flex: 1;
    flex-direction: column;
    width: 100%;
    height: 100%;
    background: #f4f4f4;
  }

  .vfe-chart {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;

    .vfe-chart-header {
      border: 1px solid #e6e9ed;
      padding: 8px;
    }

    .vfe-chart-container {
      flex: 1;
      display: flex;

      .vfe-chart-main {
        position: relative;
        flex: 1;
        max-height: ~'calc(100% - 5px)'; // fix scroll show

        .tooltip {
          position: absolute;
          display: none;
          top: 0;
          left: 0;
          width: 100px;
          height: auto;
          padding: 15px;
          border-radius: 10px;
          z-index: 999;
          opacity: 0.8;
          color: #ffffff;
          font-size: 12px;
          background-color: #000;

          p {
            margin: 0;
          }
        }
      }

      .vfe-chart-sidebar {
        float: right;
        position: relative;
        display: flex;
        justify-content: center;
        width: 200px;
        padding-top: 10px;
        background-color: #fafafa;
        border: 1px solid red;
        overflow: hidden;
      }

      .vfe-chart-panel {
        position: relative;
        width: 300px;
        background-color: #fafafa;
        border-left: 1px solid #e6e9ed;

        .vfe-chart-panel-detail {
          box-sizing: border-box;
          position: fixed;
          top: 45px;
          width: 300px;
          padding: 10px;
          height: ~'calc(100% - 250px)';
          overflow-y: auto;
        }

        .vfe-chart-panel-minimap {
          position: fixed;
          bottom: 0;
          width: 300px;
          height: 200px;
          border-top: 1px solid #e6e9ed;
        }
      }
    }
  }
</style>
